// 简易事件总线 (ES6 + TypeScript)
// 使用示例:
// import eventBus, { on, emit } from '@/utils/eventBus'
// on('my-event', (data) => { console.log(data) })
// emit('my-event', { msg: 'hello' })

export type EventBusHandler<T = any> = (payload: T) => void

class EventBus {
  // Map<事件名, Set<回调>>
  private listeners: Map<string, Set<EventBusHandler>> = new Map()

  // 注册事件
  on<T = any>(event: string, handler: EventBusHandler<T>): void {
    let set = this.listeners.get(event)
    if (!set) {
      set = new Set()
      this.listeners.set(event, set)
    }
    set.add(handler as EventBusHandler)
  }

  // 注册一次性事件
  once<T = any>(event: string, handler: EventBusHandler<T>): void {
    const wrapper: EventBusHandler<T> = (payload: T) => {
      try { handler(payload) } finally { this.off(event, wrapper) }
    }
    this.on(event, wrapper)
  }

  // 注销事件
  off<T = any>(event: string, handler: EventBusHandler<T>): void {
    const set = this.listeners.get(event)
    if (!set) return
    set.delete(handler as EventBusHandler)
    if (set.size === 0) this.listeners.delete(event)
  }

  // 派发事件
  emit<T = any>(event: string, payload: T): void {
    const set = this.listeners.get(event)
    if (!set) return
    // 拷贝一份，避免回调里增删监听影响当前循环
    for (const fn of Array.from(set)) {
      try { (fn as EventBusHandler<T>)(payload) } catch (err) {
        // 保证单个监听异常不影响其他监听
        console.error('[eventBus] 回调执行异常:', event, err)
      }
    }
  }

  // 清理某个事件或全部事件
  clear(event?: string): void {
    if (event) this.listeners.delete(event)
    else this.listeners.clear()
  }

  // 获取某事件监听数量
  listenerCount(event: string): number {
    return this.listeners.get(event)?.size || 0
  }
}

// 默认实例
const eventBus = new EventBus()
export default eventBus

// 便捷导出 (函数绑定 this)
export const on = eventBus.on.bind(eventBus) as <T = any>(event: string, handler: EventBusHandler<T>) => void
export const once = eventBus.once.bind(eventBus) as <T = any>(event: string, handler: EventBusHandler<T>) => void
export const off = eventBus.off.bind(eventBus) as <T = any>(event: string, handler: EventBusHandler<T>) => void
export const emit = eventBus.emit.bind(eventBus) as <T = any>(event: string, payload: T) => void
export const clear = eventBus.clear.bind(eventBus) as (event?: string) => void
export const listenerCount = eventBus.listenerCount.bind(eventBus) as (event: string) => number

